import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import warnings
import seaborn as sns
warnings.filterwarnings('ignore')

class ClusterUtils(object):
    # 聚类工具类
    
    def __init__(self):
        # 初始化并读取数据
        self.df = pd.read_csv('tourist_agency_visitors.csv')
    
    def get_cluster(self):
        # 获取聚类结果
        
        # 特征提取并标准化
        features = self.df[['out_province_ratio', 'elderly_ratio', 'non_weekend_visitors']]
        scaler = StandardScaler()
        scaled_features = scaler.fit_transform(features)
        
        # 执行KMeans聚类（4个簇）
        kmeans = KMeans(n_clusters=4, random_state=42)
        labels = kmeans.fit_predict(scaled_features)
        
        # 将聚类标签添加到数据框
        self.df['cluster'] = labels
        # 提取聚类中心并转换为DataFrame
        # 查看聚类中心（反标准化，还原为原始特征尺度）
        centers = scaler.inverse_transform(kmeans.cluster_centers_)
        print(pd.DataFrame(centers, columns=features.columns))

        # 保存结果
        self.df.to_csv('tourist_agency_visitors_clustered.csv', index=False)

        # 将聚类中心转换为DataFrame
        center_df = pd.DataFrame(centers, columns=features.columns)
        center_df['cluster'] = [f'cluster {i}' for i in range(centers.shape[0])]

        # 将宽表转换为长表（适合seaborn绘图）
        center_long = center_df.melt(id_vars='cluster', var_name='feature', value_name='value')

        # 绘制分组柱状图
        # 设置字体（支持中文）
        plt.rcParams["font.sans-serif"] = ["SimHei"]
        plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

        # 定义颜色
        color = ["#f77e74", "#fffd7e", "#f4c20c", "#d62728"]

        plt.figure(figsize=(10, 6))
        sns.barplot(x='feature', y='value', hue='cluster', data=center_long, palette=color)
        plt.title('聚类中心特征值对比')
        plt.xlabel('特征')
        plt.ylabel('标准化值')
        plt.legend(title='聚类', bbox_to_anchor=(1.05, 1), loc='upper left')

        # 为柱状图添加数值标签
        for p in plt.gca().patches:
            height = p.get_height()
            plt.gca().text(p.get_x() + p.get_width() / 2., height, f'{height:.2f}', ha='center')

        plt.tight_layout()  # 自动调整布局
        plt.show()


if __name__ == "__main__":
    cl = ClusterUtils()
    cl.get_cluster()
